package com.ozten.reboot;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;

import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;

import com.ozten.reboot.icasualty.Soldier;

public class RebootToRemeber {
	static boolean canExit = false;
	public static final URL REMOTE_ICASUALTY_FEED;
	static {
		try {
			REMOTE_ICASUALTY_FEED = new URL(ResourceBundle
					.getBundle("resource").getString("remote.icasualty_feed"));
		} catch (MalformedURLException e) {
			throw new IllegalStateException(
					"Bad remote casualty feed url, cannot run program", e);
		}
		System.out.println("Remote feed is at " + REMOTE_ICASUALTY_FEED);
	}

	static void okayCanExit() {
		canExit = true;
	}

	public static void main(String[] args) {
		RebootToRemeber rb = new RebootToRemeber();
		rb.run();
	}

	JFrame win = new JFrame("RebootToRemeber");
	GraphicsConfiguration config = win.getGraphicsConfiguration();
	GraphicsDevice gd = null;

	public void run() {
		while (true){
			List<Soldier> casualties = monitorForChange();
			show(casualties);
			reboot();
		}
	}

	public int mostRecentCasualty = -1;
	private long lastModified = -1;
	private String etag = "";

	public List<Soldier> monitorForChange() {
		List<Soldier> casualties = new ArrayList<Soldier>();
		while (true) {
			org.mozilla.javascript.Context cx = org.mozilla.javascript.Context
					.enter();
			try {
				Scriptable scope = new ImporterTopLevel(cx, true);

				URLConnection conn = REMOTE_ICASUALTY_FEED.openConnection();
			    if (lastModified > 0) {
					conn.setIfModifiedSince(lastModified);
				}
				if( ! etag.equals("") ){
					conn.setRequestProperty("If-None-Match", etag);
				}
				conn.setDefaultUseCaches(true);

				Reader dataIn = new InputStreamReader(conn.getInputStream());
				if (conn.getContentLength() > 0){
					lastModified = conn.getHeaderFieldDate("Last-Modified", lastModified);
					String newTag = conn.getHeaderField("ETag");
					if(newTag != null){
						etag = newTag; 
					}
					System.out.println(REMOTE_ICASUALTY_FEED.toString()	+ " last modified " + lastModified + " " + etag + " len=" + conn.getContentLength());

					cx.evaluateReader(scope, dataIn, REMOTE_ICASUALTY_FEED.toString(), 0, null);
					
					int casualtyId = casualtyIdFromJSON(scope);
					if (mostRecentCasualty != casualtyId) {
						mostRecentCasualty = casualtyId;
						memorizeNewId(casualtyId);
						Toolkit.getDefaultToolkit().beep();
						Thread.sleep(300);
						Toolkit.getDefaultToolkit().beep();
						Thread.sleep(300);
						Toolkit.getDefaultToolkit().beep();
						break;
					}
				} else {
					System.out.println("Skipping, no updates " + conn.getContentLength());
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				org.mozilla.javascript.Context.exit();
			}

			try {
				Thread.sleep(1 * 1000 * 60);// 15 minutes
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return casualties;
	}
	/* package */ int casualtyIdFromJSON(Scriptable scope){
	NativeObject o = (NativeObject) scope.get("coalition",
			scope);
	NativeArray list = (NativeArray) NativeObject.getProperty(
			o, "casualties");
	NativeObject casualty = (NativeObject) list.get(0, list);
	return Integer.parseInt((String) NativeObject
			.getProperty(casualty, "id"));
	}
	private void memorizeNewId(int casualtyId) {
		// TODO persist this id, so under restart we
		// Don't show the screen
	}

	public void show(List<Soldier> casualties) {

		win.setUndecorated(true);
		gd = GraphicsEnvironment.getLocalGraphicsEnvironment()
				.getDefaultScreenDevice();

		System.out.println("Full Screen OK? = " + gd.isFullScreenSupported());
		// win.add(new RememberComponent(casualties));
		final RememberComponent component = new RememberComponent(casualties);
		win.add(component);

		Thread t = new Thread() {
			@Override
			public void run() {
				try {
					Thread.sleep(2 * 1000);

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					component.stopRunning();
				}

			}
		};
		t.start();
		boolean doingFullScreen = gd.isFullScreenSupported();
		if (doingFullScreen) {
			gd.setFullScreenWindow(win);
		} else {
			win.setSize(Toolkit.getDefaultToolkit().getScreenSize());
			win.setVisible(true);
		}
		component.updateRenderSleep();
		if (doingFullScreen) {
			gd.setFullScreenWindow(null);
		}
		win.dispose();
	}

	public void reboot() {
		try {
			System.out.println(System.getProperty("os.name"));
			JPanel panel = new JPanel(new GridLayout(2, 1));

			JLabel passLabel = new JLabel("Enter Admin Password to Reboot");
			JPasswordField pass = new JPasswordField();
			panel.add(passLabel);
			panel.add(pass);
			int confirmed = JOptionPane.showConfirmDialog(null, panel,
					"Enter Admin Password to reboot",
					JOptionPane.OK_CANCEL_OPTION);
			String[] procArgs = { // "/usr/bin/sudo", "/sbin/shutdown", "-r",
			// "now" };
					"/bin/echo", "Shuting down" };

			Process proc = Runtime.getRuntime().exec(procArgs);
			PrintWriter out = new PrintWriter(proc.getOutputStream());

			if (confirmed >= 0) {
				System.out.println("Shutting down with "
						+ new String(pass.getPassword()));
				out.println(pass.getPassword());
			}
			final BufferedReader in = new BufferedReader(new InputStreamReader(
					proc.getInputStream()));
			String line = null;
			while (!canExit) {
				try {
					line = in.readLine();
					if (line != null) {
						System.out.println("INPUT: " + line);
					} else {
						okayCanExit();
					}

				} catch (IOException e) {
					e.printStackTrace(System.err);
				}
			}

			final BufferedReader err = new BufferedReader(
					new InputStreamReader(proc.getErrorStream()));
			Thread readErrorThread = new Thread("ReadErrorThread") {
				@Override
				public void run() {
					while (!canExit) {
						String line;
						try {
							line = err.readLine();
							if (line != null) {
								System.err.println("ERROR " + line);
							}

						} catch (IOException e) {
							e.printStackTrace(System.err);
						}
						try {
							sleep(300);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace(System.err);
						}
					}
				}
			};
			readErrorThread.start();

			try {
				proc.waitFor();

				if (proc.exitValue() != 0) {
					JOptionPane.showMessageDialog(null, "Error shutingdown",
							"Error", JOptionPane.ERROR_MESSAGE);
				}
				// System.exit(proc.exitValue());
			} catch (InterruptedException e) {
				e.printStackTrace(System.err);
			}

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (IOException e) {
			e.printStackTrace(System.err);
		}
	}
}
